﻿Imports System.ComponentModel
Imports System.IO.Ports
Imports System.Runtime.Versioning
Imports System.Threading

<SupportedOSPlatform("windows")>
<SupportedOSPlatform("linux")>
Public Class SerialClient

    <Description("轮训接收到的消息的间隔(ms)")>
    Public Property RecevingInterval As UInteger = 10

    <Description("是否在工作中")>
    Public ReadOnly Property Running As Boolean

    Public Event OnMessage As Action(Of Byte())

    Private port As SerialPort
    Private ClientReceiving As Boolean = False
    Private ClientSending As Boolean = False
    Public SendQueue As New Queue(Of Byte())

    Public Sub New(com As String, baud As UInteger)
        port = New SerialPort(com, baud)
    End Sub

    Public Sub Begin()
        _Running = True
        While True
            If Not _Running Then
                Return
            End If
            While True
                If ClientReceiving = False And
                    ClientSending = False Then
                    Exit While
                    Thread.Sleep(10)
                End If
            End While
            Try
                If Not port.IsOpen Then
                    port.Open()
                    Console.WriteLine($"Serial {port.PortName} Connected.")
                    Dim t1 = New Thread(AddressOf RecvTask)
                    Dim t2 = New Thread(AddressOf SendTask)
                    t1.Start()
                    t2.Start()
                End If
            Catch ex As Exception
                Console.WriteLine(ex.Message)
                port.Close()
                Thread.Sleep(2000)
                Console.WriteLine($"Serial {port.PortName} Reconnecting ...")
            End Try
        End While
    End Sub

    Public Sub Dispose()
        ClientReceiving = False
        ClientSending = False
        _Running = False
        port.Close()
        port.Dispose()
    End Sub

    Public Sub Write(valSendBuffer As Byte())
        If Not port.IsOpen Then Return
        SendQueue.Enqueue(valSendBuffer)
    End Sub

    Private Sub SendTask()
        Console.WriteLine($"Client {port.PortName} Start Send ...")
        ClientSending = True
        While port.IsOpen
            If SendQueue.Count > 0 Then
                Dim d = SendQueue.Dequeue()
                Try
                    port.Write(d, 0, d.Length)
                Catch ex As Exception
                    Console.WriteLine(ex.Message)
                End Try
            Else
                Thread.Sleep(1)
            End If
        End While
        ClientSending = False
        Console.WriteLine($"Client {port.PortName} Send Loop Stopped .")
        _Running = False
    End Sub

    Private Sub RecvTask()
        Console.WriteLine($"Client {port.PortName} Start Receiving...")
        ClientReceiving = True
        Dim last_bytes = 0
        While port.IsOpen
            If port.BytesToRead = last_bytes And last_bytes <> 0 Then
                Dim buf(last_bytes - 1) As Byte
                port.Read(buf, 0, last_bytes)
                'PrintBytes(buf)
                RaiseEvent OnMessage(buf)
            End If
            last_bytes = port.BytesToRead
            Thread.Sleep(RecevingInterval)
        End While
        ClientReceiving = False
        Console.WriteLine($"Client {port.PortName} Receiving Stopped.")
        _Running = False
    End Sub

End Class
